package com.sudo.api._admin;

import com.sudo.common.annotation.ApiAuthorization;
import com.sudo.common.enums.SysJobStatus;
import com.sudo.common.exception.ValidateException;
import com.sudo.common.task.BaseTaskRegistry;
import com.sudo.common.task.TaskMethod;
import com.sudo.common.task.TaskUtil;
import com.sudo.common.utils.*;
import com.sudo.dao.admin.entity.SysMethodJob;
import com.sudo.dao.admin.model.bo.*;
import com.sudo.starter.ratelimit.annotation.ApiIdempotent;
import com.sudo.service.admin.service.SysMethodJobService;
import com.sudo.service.tldata.ThreadLocalObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Slf4j
@Api(value = "方法定时任务接口",tags = {"方法定时任务管理相关的接口"})
@RestController
@RequestMapping("sysMethodJob")
public class SysMethodJobController extends AdminBaseController{

    @Resource
    private SysMethodJobService sysMethodJobService;

    @ApiOperation(value = "获取调度模块列表",notes = "获取调度模块列表",httpMethod = "GET")
    @GetMapping("/getTaskModuleMap")
    public JsonRes getTaskModuleList() {
        Map<String,String> taskModuleList = sysMethodJobService.getTaskModuleMap();
        return JsonRes.ok(taskModuleList);
    }

    @ApiOperation(value = "分页查询方法定时任务",notes = "分页查询方法定时任务",httpMethod = "GET")
    @GetMapping("/querySysMethodJobByPage")
    public JsonRes querySysMethodJobByPage(@Validated SysMethodJobQueryBO sysMethodJobQueryBO) {
        PagedGridResult pagedGridResult = sysMethodJobService.querySysMethodJobByPage(sysMethodJobQueryBO);
        return JsonRes.ok(pagedGridResult);
    }

    @ApiOperation(value = "查询定时任务",notes = "查询定时任务",httpMethod = "GET")
    @GetMapping("/querySysMethodJobById")
    public JsonRes querySysMethodJobById(@RequestParam(value = "id",required = true)Integer id) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(id);
        return JsonRes.ok(sysMethodJob);
    }

    @ApiOperation(value = "获取方法参数文档",notes = "获取方法参数文档",httpMethod = "GET")
    @GetMapping("/getMethodDocumentMap")
    public JsonRes getMethodDocumentMap() {
        Map<String, Map<String,TaskMethod>> taskMethodMap = sysMethodJobService.getMethodAndParamCountList();
        return JsonRes.ok(taskMethodMap);
    }

    @ApiOperation(value = "获取方法参数文档",notes = "获取方法参数文档",httpMethod = "GET")
    @GetMapping("/getMethodParamList")
    public JsonRes getMethodParamList(@RequestParam String beanName,@RequestParam String methodName) {
        Map<String, Map<String,TaskMethod>> taskMethodMap = sysMethodJobService.getMethodAndParamCountList();
        TaskMethod taskMethod = taskMethodMap.get(beanName).get(methodName);
        return JsonRes.ok(taskMethod.getTaskParamList());
    }

    private void validateMethodJob(String beanName, String methodName, String methodParams,String cronExpression){
        if (StringUtils.isNotBlank(cronExpression)) {
            boolean validExpression = CronExpression.isValidExpression(cronExpression);
            if (!validExpression) {
                throw new ValidateException("cron表达式不正确");
            }
        }

        Class<?> aClass = BaseTaskRegistry.getClassByBean(beanName);
        if (StringUtils.isBlank(methodParams)) {
            try{
                aClass.getDeclaredMethod(methodName);
            }catch (Exception e){
                throw new ValidateException("不存在该 "+ methodName +"() 类型的方法");
            }
        }else {
            try {
                aClass.getDeclaredMethod(methodName, Map.class);
            }catch (Exception e){
                throw new ValidateException("不存在该 "+ methodName +"(Map map) 类型的方法");
            }

            Map<String,Object> paramMap = JsonUtil.jsonToPojo(methodParams, Map.class);
            if (null == paramMap) {
                throw new ValidateException("参数格式异常，请保持Json对象格式");
            }
            boolean paramStatus = TaskUtil.verifyParam(beanName,methodName,paramMap);
            if (!paramStatus){
                throw new ValidateException("参数格式异常，请严格遵从参数类型、是否必填");
            }
        }

    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "add")
    @ApiOperation(value = "创建方法任务",notes = "创建方法任务",httpMethod = "POST")
    @PostMapping("/saveSysMethodJob")
    public JsonRes saveSysMethodJob(@RequestBody @Validated SysMethodJobSaveBO jobSaveBO,
                                    HttpServletRequest request) {
        // 子任务必须是已有任务，且不能为自己
        sysMethodJobService.verifySysMethodJobExist(-1,jobSaveBO.getNextJobIds());

        // 验证任务
        validateMethodJob(jobSaveBO.getBeanName(), jobSaveBO.getMethodName(), jobSaveBO.getMethodParams(),jobSaveBO.getCronExpression());

        String sessionUser = HttpUserInfoUtil.getSessionUser(request);
        int affectCount = sysMethodJobService.saveSysMethodJob(jobSaveBO, sessionUser);
        return JsonRes.judge(affectCount, "新增成功", "新增失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "update")
    @ApiOperation(value = "修改定时任务状态",notes = "修改定时任务状态",httpMethod = "POST")
    @PostMapping("/updateSysMethodJobStatus")
    public JsonRes updateSysMethodJobStatus(@RequestBody @Validated SysMethodJobUpdateStatusBO sysMethodJobUpdateStatusBO) {
        int affectCount = sysMethodJobService.updateSysMethodJobStatus(sysMethodJobUpdateStatusBO);
        return JsonRes.judge(affectCount, "修改成功", "修改失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "update")
    @ApiOperation(value = "编辑定时任务（不包括状态）",notes = "编辑定时任务（不包括状态）",httpMethod = "POST")
    @PostMapping("/updateSysMethodJobWithNoStatus")
    public JsonRes updateSysMethodJobWithNoStatus(@RequestBody @Validated SysMethodJobUpdateNoStatusBO jobUpdateNoStatusBO) {
        // 子任务必须是已有任务，且不能包含自己
        sysMethodJobService.verifySysMethodJobExist(jobUpdateNoStatusBO.getId(),jobUpdateNoStatusBO.getNextJobIds());

        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(jobUpdateNoStatusBO.getId());
        if (sysMethodJob == null){
            return JsonRes.errorMsg("不存在该任务");
        }
        if (SysJobStatus.RUN.name().equals(sysMethodJob.getStatus())) {
            return JsonRes.errorMsg("修改任务前必须停止该任务");
        }


        // 验证任务
        validateMethodJob(sysMethodJob.getBeanName(), sysMethodJob.getMethodName(), jobUpdateNoStatusBO.getMethodParams(),jobUpdateNoStatusBO.getCronExpression());

        int affectCount = sysMethodJobService.updateSysMethodJobWithNoStatus(jobUpdateNoStatusBO);
        return JsonRes.judge(affectCount, "修改成功", "修改失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "delete")
    @ApiOperation(value = "删除定时任务",notes = "删除定时任务",httpMethod = "POST")
    @PostMapping("/deleteSysMethodJob")
    public JsonRes deleteSysMethodJob(@RequestParam Integer id) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(id);
        if (SysJobStatus.RUN.name().equals(sysMethodJob.getStatus())) {
            return JsonRes.errorMsg("删除任务前必须停止该任务");
        }
        int affectCount = sysMethodJobService.deleteSysMethodJob(id);
        return JsonRes.judge(affectCount, "删除成功", "删除失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job", button = "run")
    @ApiOperation(value = "运行一次任务", notes = "运行一次任务", httpMethod = "POST")
    @PostMapping("/runSysMethodJob")
    public JsonRes runSysMethodJob(@RequestBody @Validated SysRunMethodJobBO runMethodJobBO) throws Exception {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(runMethodJobBO.getId());
        // 子任务必须是已有任务，且不能包含自己
        sysMethodJobService.verifySysMethodJobExist(sysMethodJob.getId(),sysMethodJob.getNextJobIds());

        // 验证任务
        validateMethodJob(sysMethodJob.getBeanName(), sysMethodJob.getMethodName(), runMethodJobBO.getMethodParams(),null);

        sysMethodJob.setMethodParams(runMethodJobBO.getMethodParams());
        Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(sysMethodJob);
        ThreadLocalUtil.setTlMap(jobConfigMap);
        TaskUtil.callTaskMethod(sysMethodJob.getBeanName(),sysMethodJob.getMethodName(),sysMethodJob.getMethodParams());
        return JsonRes.okMsg("执行成功");
    }

}
